package org.eclipse.epsilon.emc.rdbms.core.persistanttransaction;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.util.ArrayList;
import java.util.HashMap;

import org.eclipse.epsilon.emc.rdbms.core.customexceptions.CustomException;
import org.eclipse.epsilon.emc.rdbms.core.persistancebroker.PersistanceBroker;
import org.eclipse.epsilon.emc.rdbms.core.persistancemechanism.RelationalDatabase;

public class PersistanceTransaction
{
	static ArrayList<Object> tasks = new  ArrayList<Object>();	      	   
	static Connection Connection;
	int retryCount = 0;
	int transactioncount=0;

	/** This method is called when we want to process the transactions which have been added to the tasks list .
	*@return the result of the SQL statement issued.
	*/	 
	public ResultSet processTransaction() throws SQLException 
	{
		String statement = "";
		for (int i=0;i<tasks.size();i++)
		{
			statement = statement + tasks.get(i).toString()+";";
		}
		try 
		{
			ResultSet result = PersistanceBroker.processSql(statement);
			tasks.clear(); //Once all the tasks have been processed then we must clear the list of pending statements.
			return result;
		}
		catch (SQLException e) 
		{
			if(retryCount==0)
			{
				retryCount++;
				retryTransaction();  //retry the transaction as there may have been a network issue between the app and database server.
			}
			else 
			{
				
				new CustomException("ERROR: Persistance Transaction - Unable to process transaction: "+e.getMessage());
				rollbackTransaction();
				
			}
		}
		return null;
	}


	/** This method is used to retry a transaction oif it fails, for example there could be a network issue that is a minor issue and we would like to retry the transaction..
	*/	 
	public void retryTransaction() throws SQLException
	{
		processTransaction();	//Try and process the transaction again.
	}

	/** This method is used to create a new transaction
	*/	 
	public void addTransaction() throws SQLException
	{
		transactioncount++;
		Connection = PersistanceBroker.connectTo().open();
		Connection.setAutoCommit(false);
		Connection.setSavepoint();
	}

	/** This method is used to get the current connection for the transaction
	@return connection the current connection to the database.
	*/	 
	public static Connection getConnection()
	{
		return Connection;
	}

	/** This method is used to add the object to the task list which will be processed when processTransaction() is called.
	*@param command - The specific SQL statement that will be run
	*/	 
	public static void saveObject(Object command)
	{	
		tasks.add(command);		
	}

	/** This method is used to retrieve the next item from the task list to be executed.
	*@param index - index of the item to be retrieved
	*@return The string of the task to be executed next.
	*/	 
	public String retrieveObject(int index)
	{
		return tasks.get(index).toString();	  //Retreieve the command at index i.
	}

	/** This method is used to delete a command from the task list should the task no longer be required.
	*@param command - The task object to be deleted from the task list.
	*@return null
	*/	
	public void deleteObject(Object command)
	{
		tasks.remove(command);        //Delete a specific command Object.
	}

	/** This method is used to rollback the transacyion
	*/	
	public void rollbackTransaction() throws SQLException
	{
		transactioncount--;
		Connection.rollback();
		if(transactioncount ==0) 
		{
			Connection.setAutoCommit(true);  //We only want to put it back into Auto commit mode if the transaction count  = 0 used for nested transactions.
		}
	}

	/** This method is used to commit the transaction to the database,
	*/	
	public void commitTransaction() throws SQLException
	{	
		transactioncount--;
		Connection.commit();
		tasks.clear(); 
		if(transactioncount ==0) 
		{
			Connection.setAutoCommit(true);  //We only want to put it back into Auto commit mode if the transaction count  = 0 used for nested transactions.
		}
	}
}
